#pragma once

#include "zen_vap_sprite.h"
#include "zen_vap_figure.h"
#include "zen_font.h"
#include "zen_class.h"
#include <vector>
#include <mutex>

namespace Zen { namespace Vap {

	class TextureWithRender {
	public:

		std::shared_ptr<FontRender> getFontRender() { return m_render; }

		void setFontRender(std::shared_ptr<FontRender> render);

		void setImageEffect(ImageEffectFunction effect);

		auto getImageEffect() { return m_image_effect; }

		void setUnderlineInPixels(int width);

		bool clearRenderDirty();

		SharedTexture getTextureRendered();

	private:

		std::shared_ptr<FontRender> m_render;

		ImageEffectFunction m_image_effect;

		std::shared_ptr<Image> m_image;

		int m_underline_px = 0;

		bool m_is_render_dirty = false;

		bool m_is_image_dirty = false;

		bool m_is_texture_empty = true;

		SharedTexture m_texture_rendered;
	};

	/*!
	 @class
	 @abstract a font label. <br>
	 the label use a font to render view, it's a slowly operation. <br>
	 so not good for dynamic text.
	 */
	class FontLabel : public Sprite, public TextureWithRender {

	public:
		FontLabel(std::string const & name = "label");

		void setFontBrush(std::shared_ptr<FontBrush>);

		std::shared_ptr<FontBrush> getFontBrush() { return m_font; }

		void setFontSize(float size);

		auto getFontSize() const { return m_font_size; }

		bool clearFontDirty();

		virtual void load() override;

		virtual void ready() override;

		virtual void draw() override;

	public:
		// render config.
		void setTextAlignment(float alignment);

		void setMaxWidthInPixels(int pixels);

		void setCharsSpacingInPixels(int pixels);

		void setLinesSpacingInPixels(int pixels);

		float getTextAlignment() { return m_alignment; }

		int getMaxWidthInPixels() { return m_max_width_px; }

		int getCharsSpacingInPixels() { return m_char_spacing_px; }

		int getLinesSpacingInPixels() { return m_line_spacing_px; }

		void setText(std::string const & str);

		std::string const & getText() const { return m_text; }

	protected:

		std::string m_text;
		std::u32string m_text32;
		float m_alignment = 0;
		int m_max_width_px = 0;
		int m_char_spacing_px = 0;
		int m_line_spacing_px = 0;
		bool m_is_page_dirty = true;

	protected:
		float m_font_size = 16;

		bool m_is_font_brush_dirty = true;
		bool m_is_font_size_dirty = true;

		std::shared_ptr<FontBrush> m_font;

		using Sprite::setTexture;
		using Sprite::setTextureScale;

		using TextureWithRender::setFontRender;
	};
}}


/// Tilemap


namespace Zen { namespace Vap {

	/**
	 00 -- 10
	 |      |
	 |      |
	 01 -- 11
	 */
	struct TileCharCoords {
		Vec2 tex_coord00;
		Vec2 tex_coord11;
		Size2 view_size;
	};

	class TilemapFont {
	public:
		void load(SharedTexture texture, Rect4f area, char32_t start_code, int x_count, int y_count);

	public:
		TileCharCoords const * getTile(char32_t unicode);

		SharedTexture getTexture() { return m_texture; }

		Rect4f getTextureRect() { return m_texture_area; }

//		void setNotFoundIndex(char32_t index) { m_not_found_index = index; }
//
//		char32_t getNotFoundIndex() const { return m_not_found_index; }
	protected:
		SharedTexture m_texture;
		Rect4f m_texture_area;
		char32_t m_start_code = 0;
//		char32_t m_not_found_index = -1;
		int m_x_count = 1;
		int m_y_count = 1;
		int m_count = 1;

		std::map<char32_t, TileCharCoords> m_tile_char_coords;
	};

	class TilemapLabel
	: public Node2D, public PartOfMatrix2D
	, public PartOfColor, public PartOfFlip {
	public:
		TilemapLabel();

		void setTileMap(std::shared_ptr<TilemapFont> map);

	public:
		void setCharSpacing(float x);

		void setText(std::string const & s);

		void setContentSize(Size2 size);

		void setContentSizeWithWidth(float w);

		void setContentSizeWithHeight(float h);

		void setContentSize();

		Size2 getContentSize();

		void updateContent();

	public:

		virtual void draw() override;

		virtual void ready() override;
#if ZEN_APP_GLES
	public:
		/*!
		 @function
		 @abstract set the shader selector. <br>
		 see ref class ShaderKit
		 */
		void setShaderSelector(GL::ShaderKitTexture::Selector s) { m_shader_selector = s; }

		auto getShaderSelector() { return m_shader_selector; }

	protected:
//		static GL::DrawBufferTexture s_gl_buffer;
		GL::ShaderKitTexture::Selector m_shader_selector;
#endif
	protected:
		std::vector<GL::VertexDataTexture> m_vertexes;

		float m_spacing_x = 0;
//		float m_spacing_y = 0;
		std::string m_text;
		std::u32string m_text_u32;

		bool m_is_font_dirty = false;

		Vec4 m_texture_rect_converted = { 0, 0, 1, 1 };

		Size2 m_fixed_size;
		Size2 m_auto_size;
		bool m_is_fixed_size = false;

	protected:
		bool m_is_gl_buffer_dirty = false;
		GL::DrawBuffer<GL::VertexDataTexture> m_gl_buffer;

	protected:

		std::shared_ptr<TilemapFont> mTileMap;
	};
}}

